"""
!/usr/bin/env python
-*- coding: utf-8 -*-
@Author  : MarkJia
@Site    : 
@File    : 19、优化电子商务代码.py
"""

"""
问题1 ： 新增商品用例 产生了脏数据
        解决方案 ： 清理对应的脏数据 --   清理的方式可以通过 接口 和 ui
问题2 : 
        代码存在大量的强制等待
        解决方案 ： 使用 显式等待 替换 强制等待
"""

# pytest .\19、优化电子商务代码.py --alluredir ./allure_report --clean-alluredir
# allure serve ./allure_report
import allure
import time
import logging
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions


# 日志配置
def get_logger():
    # 创建 logger 实例
    logger = logging.getLogger('simple_example')
    # 设置日志级别
    logger.setLevel(logging.DEBUG)
    # 流处理器
    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    # 日志打印格式
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    # 添加格式设置
    ch.setFormatter(formatter)
    # 添加日志配置
    logger.addHandler(ch)

    return logger


logger = get_logger()


class TestLitemall:

    def setup_class(self):
        self.driver = webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.implicitly_wait(5)
        self.driver.get('http://litemall.hogwarts.ceshiren.com')
        # 先清空，在输入内容
        self.driver.find_element(By.CSS_SELECTOR, '[name="username"]').clear()
        self.driver.find_element(By.CSS_SELECTOR, '[name="username"]').send_keys('manage')

        self.driver.find_element(By.XPATH, '//input[@name="password"]').clear()
        self.driver.find_element(By.XPATH, '//input[@name="password"]').send_keys('manage123')
        # 点击登录按钮
        self.driver.find_element(By.CSS_SELECTOR, '.el-button--primary').click()

    def teardown_class(self):
        self.driver.quit()

    def get_screen(self):
        timestamp = int(time.time())
        # 一定要提前创建好 images 路径
        image_path = f'./image/image_{timestamp}.PNG'
        # 截图
        self.driver.save_screenshot(image_path)
        # 将 截图 放到报告中
        allure.attach.file(image_path, name='picture', attachment_type=allure.attachment_type.PNG)

    # ==================================== 自定义 ： 显式等待优化  =================================================
    def click_exception(self, by, element, max_attempts=5):
        def _inner(driver):
            # 多次点击按钮
            actul_attempts = 0  # 实际点击次数
            while actul_attempts < max_attempts:
                actul_attempts += 1  # 每次循环，实际次数点击加1
                try:
                    # 如果点击过程中报错，则直接执行 except 逻辑，并且继续循环。没有报错，直接 return 循环结束
                    driver.find_element(by, element).click()
                    return True
                except Exception:
                    print('在点击动作时报错')
                    logger.debug('在点击动作时报错')
            # 当实际点击次数 > 最大点击次数时，结束循环并抛出异常
            raise Exception('超出最大点击次数')

        return _inner

    # 添加商品功能
    def test_add_merchandise(self):
        # 首页，点击商场管理
        self.driver.find_element(By.XPATH, '//*[text()="商场管理"]').click()
        # 点击商品类目 -> 进入商品类目页面
        self.driver.find_element(By.XPATH, '//*[text()="商品类目"]').click()
        # 点击添加
        self.driver.find_element(By.XPATH, '//span[text()="添加"]').click()
        self.driver.find_element(By.CSS_SELECTOR, ".el-input__inner").send_keys('新增商品测试')

        # 点击确定按钮  -> 使用显式等待，直到 元素可以被点击
        # ele = WebDriverWait(self.driver, 10).until(
        #     expected_conditions.element_to_be_clickable((By.CSS_SELECTOR, '.dialog-footer .el-button--primary')))
        # ele.click()

        WebDriverWait(self.driver, 10).until(
            self.click_exception(By.CSS_SELECTOR, '.dialog-footer .el-button--primary'))

        # 获取 实际结果
        # 使用 find_elements ，如果找不到元素，会返回空列表。 find_element ，如果找不到，会报错
        res_list = self.driver.find_elements(By.XPATH, "//*[text()='新增商品测试']")
        # 截图和 allure
        self.get_screen()

        # 日志
        actul = [i.text for i in res_list]
        logger.info(f'获取到的实际结果为{actul}')

        # 清理环境 ： 删除用例生成的脏数据   - >  数据的清理一定要放在断言之后完成。否则会影响用例的断言结果
        self.driver.find_element(By.XPATH, "//*[text()='新增商品测试']/../..//*[text()='删除']").click()

        # 断言产品新增后是否成功找到。如果找到，证明新增成功
        assert res_list != []
        assert '新增商品测试' in [i.text for i in res_list]

    # 删除商品功能
    def test_delete(self):
        # 首页，点击商场管理
        self.driver.find_element(By.XPATH, '//*[text()="商场管理"]').click()
        # 点击商品类目 -> 进入商品类目页面
        self.driver.find_element(By.XPATH, '//*[text()="商品类目"]').click()
        # 添加 ： 删除商品测试
        # 点击添加
        self.driver.find_element(By.XPATH, '//span[text()="添加"]').click()
        # 定位的元素表达式存在多个值，只需要取第一个值，可以直接使用
        self.driver.find_element(By.CSS_SELECTOR, ".el-input__inner").send_keys('删除商品测试')
        # 点击确定按钮
        WebDriverWait(self.driver, 10).until(self.click_exception(By.XPATH, '//span[text()="确定"]'))
        # ========================================  完成删除操作  ======================================================
        # 点击删除按钮  : 通过 子元素 查找 父元素
        self.driver.find_element(By.XPATH, "//*[text()='删除商品测试']/../..//*[text()='删除']").click()

        # 截图和 allure
        self.get_screen()

        # 断言 ： 删除之后，这个商品类目是否还能获取到。如果删除成功，则会消失
        # 问题： 因为代码执行速度快，元素还未消失就捕获了
        # 解决方案 ： 确认该元素不存在后，再捕获
        WebDriverWait(self.driver, 10).until_not(
            expected_conditions.visibility_of_any_elements_located((By.XPATH, "//*[text()='删除商品测试']")))
        res_list1 = self.driver.find_elements(By.XPATH, "//*[text()='删除商品测试']")
        # 日志
        logger.info(f'获取到的实际结果为{res_list1}')
        assert res_list1 == []
